feat(sdk): add webhook helper for forward-route handlers#419
Merged
Conversation
73fc765 to
62aaff5
Compare
62aaff5 to
e91aff6
Compare
declan-scale
left a comment
Contributor
There was a problem hiding this comment.
A couple questions, also wondering if we want to wait for the resolve pr to land and put it in the sgp sdk and then use that rather than raw fetch.
smoreinis
reviewed
Jun 22, 2026
smoreinis
reviewed
Jun 22, 2026
e91aff6 to
0d11673
Compare
0d11673 to
66a3997
Compare
Contributor
|
this looks good to me! i'll let Declan give the final approve since he had some other comments here too, lmk if you need a stamp |
declan-scale
approved these changes
Jun 23, 2026
66a3997 to
80231e0
Compare
Contributor
Author
|
Rebased this branch onto origin/main and force-pushed the updated head: 80231e0. What changed during the rebase:
Verified locally:
Note: GitHub still shows the PR as BEHIND because the PR base is currently next, while this branch is rebased onto main as requested. |
Add agentex.lib.sdk.utils.webhooks.handle_webhook — a reusable helper an agent
calls from a forward-route handler (@acp.post on the route the server's
/agents/forward/name/{agent}/{path} ingress proxies to). It shapes the payload
(generic or GitHub PR), resolves task params (inline or fetched from a config
resolve URL for config-by-id), get-or-creates a task on a stable session key so
repeat events fold into one task, drives the turn (sync message / async event),
and returns/polls the reply.
This keeps webhook triggering on the supported forward mechanism + its built-in
GitHub/Slack signature auth, instead of a parallel ingress. Config-by-id is
ingress-independent: point params_source at the platform's config-resolve endpoint.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
80231e0 to
b03fdd0
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds
agentex.lib.sdk.utils.webhooks.handle_webhook— a reusable helper an agent calls from a forward-route handler (a@acp.post(...)route that the server's/agents/forward/name/{agent}/{path}ingress proxies to).It does, agent-side via
adk:params_sourceURL (config-by-id; the platform's config-resolve endpoint),message/sendreturns the reply inline; asyncevent/send, with optionalwaitto poll),Why
Triggering an agent from a webhook is already supported via the forward mechanism (which has built-in GitHub/Slack signature auth). This helper provides the shaping/resolve/dispatch convenience on that supported path instead of a parallel ingress, so an agent's webhook handler is ~10 lines.
Before — every agent hand-writes the full pipeline in its handler: shape the raw payload into a prompt, fetch+map the config, hash a stable session key, get-or-create the task, dispatch, then dig the reply back out of the message list. Each agent re-implements the edge cases (diff truncation, sync vs async, id-less messages) and gets them wrong in its own way.
After — the same five steps become keyword arguments; the messy implementation lives once in
webhooks.py:Config-by-id is ingress-independent: point
params_sourceat the platform's config-resolve endpoint (the scaleapiGET /v5/agent_configs/{id}/resolveserver-side counterpart) and the resolved params are forwarded opaquely totask/create.Design notes (open-source SDK)
This module ships in the open-source SDK, so two things were kept deliberate:
params_source_headers(docstring uses.../<host>placeholders). It shapes only public webhook formats (GitHub/Gitea/Slack) and forwards opaque params; the config-resolve endpoint is referenced generically, not by an internal URL. Self-contained leaf module (adk+ stdlib).shape_github_premits facts only (title / action / URL / description / diff) — no "review this PR" instruction is baked in. The actual task lives in the config'ssystem_prompt, not the helper. The opinionated parts (shaperenumgeneric/github_pr;MAX_BODY_CHARS/MAX_DIFF_CHARSconstants) are opt-in conveniences over a fully-generic base —shaper="generic"+ inlineparamssidesteps both, so nothing traps the user. (fetchis injectable;shaperis currently a closed enum.)Testing
tests/lib/test_webhooks.py): session-key folding, generic + GitHub-PR shaping, params/config-by-id resolution (envelope + bare-object + error), andhandle_webhooksync/async withadkmocked. ruff clean.🤖 Generated with Claude Code
Greptile Summary
This PR adds
agentex.lib.sdk.utils.webhooks.handle_webhook, a reusable helper for forward-route handlers that consolidates the five-step pipeline (shape → resolve params → get-or-create task → dispatch → extract reply) that every webhook-driven agent was previously hand-rolling.render_genericandshape_github_prconvert raw webhook bodies into a structured prompt, withpeer_id-based session continuity so repeated PR events fold into one task instead of spawning new ones.paramsor a remoteparams_sourceURL; resolved params are forwarded opaquely totask/create, and source-returned metadata is merged onto the task (canonical fields win)._await_replysnapshots pre-event message ids and count so a reused task's prior reply is never returned as the new one; id-less messages are handled via positional boundary.Confidence Score: 4/5
Safe to merge after resolving the inline-params-plus-params_source silent data loss.
The module is well-structured and regression tests cover session-continuity, metadata-merge, stale-reply, and id-less message scenarios. The one present defect is that inline params are silently overwritten when params_source is also provided, with no warning or error surfaced to the caller.
src/agentex/lib/sdk/utils/webhooks.py — handle_webhook params resolution block (lines 283-287)
Important Files Changed
Reviews (7): Last reviewed commit: "Merge branch 'next' into dm/sdk-webhook-..." | Re-trigger Greptile